home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 388_01 / ae / 93 / jul / gap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-06  |  5.4 KB  |  316 lines

  1. /*
  2.  * gap.c        
  3.  *
  4.  * Anthony's Editor July 93
  5.  *
  6.  * Copyright 1993, 1993 by Anthony Howe.  All rights reserved.  No warranty.
  7.  */
  8.  
  9. #include <ctype.h>
  10. #include <fcntl.h>
  11. #include <sys\types.h>
  12. #include <sys\stat.h>
  13. #include "header.h"
  14.  
  15. typedef struct t_undo {
  16.     short u_set;
  17.     t_point u_point;
  18.     t_point u_gap;
  19.     t_point u_egap;
  20. } t_undo;
  21.  
  22. static t_undo ubuf;
  23.  
  24. /*
  25.  *    Enlarge the gap by n characters.  
  26.  *    Note that the position of the gap cannot change.
  27.  */
  28. int
  29. growgap(n)
  30. t_point n;
  31. {
  32.     t_char *new;
  33.     t_point buflen, newlen, xgap, xegap;
  34.     
  35.     assert(buf <= gap);
  36.     assert(gap <= egap);
  37.     assert(egap <= ebuf);
  38.  
  39.     xgap = gap - buf;
  40.     xegap = egap - buf;
  41.     buflen = ebuf - buf;
  42.     newlen = buflen + n * sizeof (t_char);
  43.  
  44.     if (buflen == 0) {
  45.         if (newlen < 0 || MAX_SSIZE_T < newlen)
  46.             fatal(f_alloc);
  47.         new = (t_char*) malloc((size_t) newlen);
  48.         if (new == NULL)
  49.             /* Cannot edit a file without a buffer. */
  50.             fatal(f_alloc);
  51.     } else {
  52.         if (newlen < 0 || MAX_SSIZE_T < newlen) {
  53.             msg(m_alloc);
  54.             return (FALSE);
  55.         }
  56.         new = (t_char*) realloc(buf, (size_t) newlen);
  57.         if (new == NULL) {
  58.             /* Report non-fatal error. */
  59.             msg(m_alloc);
  60.             return (FALSE);
  61.         }
  62.     }
  63.  
  64.     /* Relocate pointers in new buffer and append the new 
  65.      * extension to the end of the gap. 
  66.      */
  67.     buf = new;
  68.     gap = buf + xgap;    
  69.     ebuf = buf + buflen; 
  70.     egap = buf + newlen;
  71.     while (xegap < buflen--)
  72.         *--egap = *--ebuf;
  73.     ebuf = buf + newlen;
  74.  
  75.     assert(buf < ebuf);        /* Buffer must exist. */
  76.     assert(buf <= gap);
  77.     assert(gap < egap);        /* Gap must grow only. */
  78.     assert(egap <= ebuf);
  79.  
  80.     return (TRUE);
  81. }
  82.  
  83. /*
  84.  *
  85.  */
  86. t_point
  87. movegap(offset)
  88. t_point offset;
  89. {
  90.     t_char *p = ptr(offset);
  91.     while (p < gap)
  92.         *--egap = *--gap;
  93.     while (egap < p)
  94.         *gap++ = *egap++;
  95.     assert(gap <= egap);
  96.     assert(buf <= gap);
  97.     assert(egap <= ebuf);
  98.     return (pos(egap));
  99. }
  100.  
  101. /*
  102.  * Return pointer on range buf <= ptr(offset) <= ebuf.
  103.  */
  104. t_char *
  105. ptr(offset)
  106. register t_point offset;
  107. {
  108.     register t_char *cp;
  109.  
  110.     if (offset < 0)
  111.         return (buf);
  112.     cp = buf + offset;
  113.     if (gap <= cp)
  114.         cp += (unsigned long)(egap - gap);
  115.     if (ebuf <= cp)
  116.         return (ebuf);
  117.     return (cp);
  118. }
  119.  
  120. /*
  121.  * Return offset on range 0 <= pos(pointer) <= pos(ebuf).
  122.  */
  123. t_point
  124. pos(cp)
  125. register t_char *cp;
  126. {
  127.     register t_point offset;
  128.  
  129.     offset = (t_point)(cp - buf);
  130.     if (cp < buf)
  131.         return (0);
  132.     if (ebuf <= cp)
  133.         cp = ebuf;
  134.     if (egap <= cp)
  135.         offset -= (unsigned long)(egap - gap);
  136.     return (offset);
  137. }
  138.  
  139. /*
  140.  * Return the current region.
  141.  */
  142. void
  143. getregion(rp)
  144. t_region *rp;
  145. {
  146.     if (marker == NOMARK) {
  147.         rp->left = rp->right = point;
  148.     } else if (point <= marker) {
  149.         rp->left = point;
  150.         rp->right = marker-1;
  151.     } else {
  152.         rp->left = marker;
  153.         rp->right = point-1;
  154.     }
  155. }
  156.  
  157. int
  158. posix_file(fn)
  159. char *fn;
  160. {
  161.     if (fn[0] == '\0' || fn[0] == '_')
  162.         return (FALSE);
  163. #ifdef DRIVE_COLON
  164.     if (fn[1] == ':') {
  165.          if (!isalpha(fn[0]))
  166.             return (FALSE);
  167.         fn += 2;
  168.     }
  169. #endif /* DRIVE_COLON */
  170.     for (; *fn != '\0'; ++fn) {
  171.         if (!isalnum(*fn) && *fn != '.' && *fn != '_' && *fn != '-' 
  172. #ifdef EITHER_SLASH
  173.         && *fn != '/' && *fn != '\\')
  174. #else
  175.         && *fn != '/')
  176. #endif /* EITHER_SLASH */
  177.             return (FALSE);
  178.     }
  179.     return (TRUE);
  180. }
  181.  
  182. /*
  183.  *
  184.  */
  185. int
  186. save(fn)
  187. char *fn;
  188. {
  189.     int fd;
  190.     t_point llen, rlen;
  191.     t_char *lhalf, *rhalf;
  192.  
  193.     if (!posix_file(fn)) {
  194.         msg(m_badname);
  195.         return (FALSE);
  196.     }
  197.  
  198.     if ((fd = open(fn, O_WRONLY|O_CREAT|O_TRUNC, FILE_MODE)) < 0) {
  199.         msg(m_open, fn);
  200.         return (FALSE);
  201.     }
  202.     if (marker == NOMARK || point == marker) {
  203.         lhalf = buf;
  204.         llen = (t_point) (gap - buf);
  205.         rhalf = egap;
  206.         rlen = (t_point) (ebuf - egap);
  207.     } else {
  208.         /* When saving only a block of text, we'll move the gap
  209.          * to the start of the block, and set the left-half to
  210.          * zero length.  We should never see the error message
  211.          * in the saved block of text. 
  212.          */
  213.         llen = 0;
  214.         lhalf = (t_char *) m_error;
  215.         if (point < marker) {
  216.             (void) movegap(point);
  217.             rlen = marker - point;
  218.         } else {
  219.             (void) movegap(marker);
  220.             rlen = point - marker;
  221.         }
  222.         rhalf = egap;
  223.     }
  224.  
  225.     if (write(fd, lhalf, (size_t) llen) != llen
  226.     || write(fd, rhalf, (size_t) rlen) != rlen) {
  227.         msg(m_write, fn);
  228.         return (FALSE);
  229.     }
  230.     if (close(fd) != 0) {
  231.         msg(m_close, fn);
  232.         return (FALSE);
  233.     }
  234.  
  235.     if (lhalf != (t_char *) m_error)
  236.         modified = FALSE;
  237.     msg(m_saved, fn, llen + rlen);
  238.     return (TRUE);
  239. }
  240.  
  241. /*
  242.  *
  243.  */
  244. int
  245. load(fn)
  246. char *fn;
  247. {
  248.     int fd;
  249.     SSIZE_T len;
  250.     struct stat sb;
  251.  
  252.     if (stat(fn, &sb) < 0) {
  253.         msg(m_stat, fn);
  254.         return (FALSE);
  255.     }
  256.     if (MAX_SSIZE_T < sb.st_size) {
  257.         msg(m_toobig, fn);
  258.         return (FALSE);
  259.     }
  260.     if (egap-gap < sb.st_size * sizeof (t_char) && !growgap(sb.st_size))
  261.         return (FALSE);
  262.     if ((fd = open(fn, O_RDONLY)) < 0) {
  263.         msg(m_open, fn);
  264.         return (FALSE);
  265.     }
  266.     point = movegap(point);
  267.     undoset();
  268.  
  269.     len = read(fd, gap, (size_t) sb.st_size);
  270.     if (close(fd) != 0) {
  271.         msg(m_close, fn);
  272.         return (FALSE);
  273.     }
  274.     if (len < 0) {
  275.         msg(m_read, fn);
  276.         return (FALSE);
  277.     }
  278.  
  279.     gap += len;
  280.     modified = TRUE;
  281.     msg(m_loaded, fn, len);
  282.     return (TRUE);
  283. }
  284.  
  285. /*
  286.  *    Record a new undo location.
  287.  */
  288. void
  289. undoset()
  290. {
  291.     ubuf.u_set = TRUE;
  292.     ubuf.u_point = point;
  293.     ubuf.u_gap = gap - buf;
  294.     ubuf.u_egap = egap - buf;
  295. }
  296.  
  297. /*
  298.  *    Undo.
  299.  */
  300. void
  301. undo()
  302. {
  303.     t_undo tmp;
  304.  
  305.     if (ubuf.u_set) {
  306.         memcpy(&tmp, &ubuf, sizeof (t_undo));
  307.         undoset();
  308.         point = tmp.u_point;
  309.         gap = buf + tmp.u_gap;
  310.         egap = buf + tmp.u_egap;
  311.     } else {
  312.         msg(m_undo);
  313.     }
  314. }
  315.  
  316.